package DEEPERsource.DEEPERsource.source.machinelearning.javaml;

import java.util.Arrays;
import java.util.Collection;
import java.util.Vector;

import deeper.Interaction;

import machinelearning.kernel.Kernel;
import net.sf.javaml.core.Instance;
import net.sf.javaml.core.SimpleDataset;

public class PrecomputedDataset extends SimpleDataset{

	private boolean recalculate = false;
	private boolean locked = false;
	
	private Vector<Interaction> originals = new Vector<Interaction>();
	
	private Kernel<Interaction> kernel;
	
	public PrecomputedDataset() {}

    public PrecomputedDataset(Vector<Interaction> data) {
    	recalculate = true;
        this.addAllOriginals(data);
    }
    
    public boolean addAllOriginals(Vector<Interaction> data){
    	if(locked)
    		return false;
    	for(Interaction g : data){
    		originals.add(g);
    	}
    	recalculate = true;
    	return true;
    }
    
    public boolean addOriginal(Interaction g){
    	if(locked)
    		return false;
    	recalculate = true;
    	return originals.add(g);
    }

    public boolean addAll(Collection<? extends Instance> c) {
    	throw new RuntimeException("AddAll is not imlpemented in precomputed dataset.");
	}
	
	public boolean add(Instance i) {
		throw new RuntimeException("Add is not imlpemented in precomputed dataset.");
	}
	
	public void sort(int index){
		throw new RuntimeException("Sort is not imlpemented in precomputed dataset.");
	}
	
	public Instance instance(int index) {
		recalculate();
        return super.instance(index);
    }
	
	public Interaction originalInstance(int i){
		return originals.get(i);
	}
	
	public Vector<Interaction> originals(){
		return originals;
	}

	public boolean isLocked(){
		return locked;
	}
	
	public void lock(boolean arg){
		locked = arg;
	}
	
	public void setKernel(Kernel<Interaction> kernel){
		this.kernel = kernel;
	}
	
	private void recalculate(){
		if(recalculate){
			int newPart = size();
			int newPartEnd = originals.size();
			//recalculating old instances
			for(int i = 0; i < newPart; i++){
				Interaction g1 = originals.get(i);
				int j = 0;
				for(Instance inst : this){
					Interaction g2 = originals.get(j);
					if(inst instanceof ExtendableInstance)
						((ExtendableInstance)inst).addValue(kernel.compute(g1, g2));
					else
						throw new RuntimeException("Instance should be of ExtendableInstance type");					
				}
			}
			//adding new instances
			for(int i = newPart; i < newPartEnd; i++){
				Interaction g1 = originals.get(i);
				Vector<Double> values = new Vector<Double>();
				for(Interaction g2 : originals)
					values.add(kernel.compute(g1, g2));
				ExtendableInstance inst = new ExtendableInstance(values);
				super.add(inst);
			}
			recalculate = false;
		}
	}
}
